<!--
 * Copyright © 2023
 * @Author: zhangxiang
 * @Date: 2023-05-23 17:14:34
 * @LastEditors: zhangxiang
 * @LastEditTime: 2023-09-21 15:36:56
 * @Description:
 *
-->

<template>
  <MyContainer class="container">
    <MyHeader class="header">
      <span class="name">应用类型</span>
      <el-select
        v-model="category"
        placeholder="请选择应用类型"
        size="medium"
        style="width: 100px; margin-left: 10px; margin-right: 20px"
        @change="categoryChange"
      >
        <el-option
          v-for="item in categoryOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
      <span class="name">应用场景</span>
      <el-select
        v-model="scene"
        placeholder="请选择应用场景"
        size="medium"
        style="width: 170px; margin-left: 10px; margin-right: 20px"
        filterable
        remote
        :remote-method="sceneRemoteQuery"
        :loading="sceneLoading"
        @change="sceneChange"
      >
        <el-option
          v-for="item in sceneOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
      <span class="name">指标类型</span>
      <el-select
        v-model="indicatorType"
        placeholder="请选择指标类型"
        clearable
        size="medium"
        style="width: 150px; margin-left: 10px; margin-right: 20px"
        @change="indicatorTypeChange"
      >
        <el-option
          v-for="item in indicatorTypeOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
      <span class="name">指标名称</span>
      <el-select
        v-model="indicatorName"
        placeholder="请选择指标名称"
        size="medium"
        style="width: 170px; margin-left: 10px; margin-right: 20px"
        filterable
        remote
        :remote-method="indicatorNameRemoteQuery"
        :loading="indicatorNameLoading"
        @change="indicatorNameChange"
      >
        <el-option
          v-for="item in indicatorNameOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
      <el-button
        size="medium"
        type="primary"
        :loading="loading"
        @click="queryClick"
      >查询</el-button>
      <el-button size="medium" @click="resetClick">重置</el-button>
      <el-button
        size="medium"
        type="primary"
        :loading="exportLoading"
        style="margin-left: auto"
        @click="exportClick"
      >导出</el-button>
    </MyHeader>
    <MyMain class="main">
      <div class="jsmind-wrapper">
        <div
          v-if="showMind"
          id="jsmind_container"
          class="jsmind-ctn"
          @click="jsmindCtnClick"
        ></div>
      </div>
    </MyMain>

    <TrendDialog
      v-if="showTrendDialog"
      :show.sync="showTrendDialog"
      :info="trendInfo"
    />
  </MyContainer>
</template>

<script>
import MyContainer from '@/components/Layout/MyContainer'
import MyHeader from '@/components/Layout/MyHeader'
import MyMain from '@/components/Layout/MyMain'
import {
  getIndicatorScene,
  getIndicatorName,
  getIndicatorCase,
  getMesaureExport
} from '@/api/cnap/scheduling-engine'
import jsMind from 'jsmind'
import 'jsmind/style/jsmind.css'
import TrendDialog from './components/TrendDialog'
import { isEmptyString } from '@/utils/index'

const APP_CATEGORY = [
  {
    label: 'AI',
    value: 'AI'
  }
]
const INDICATOR_TYPE = [
  {
    label: '算力度量',
    value: '算力度量'
  },
  {
    label: '网络度量',
    value: '网络度量'
  }
]
const MIND_STYLES = [
  {
    backgroundColor: '#FEFEFF',
    foregroundColor: '#E04FDC',
    fontSize: 18
  },
  {
    backgroundColor: '#2CCDE3',
    foregroundColor: '#FFFFFF',
    fontSize: 18
  },
  {
    backgroundColor: '#A160F4',
    foregroundColor: '#FFFFFF',
    fontSize: 16
  },
  {
    backgroundColor: '#F46086',
    foregroundColor: '#FFFFFF',
    fontSize: 18
  },
  {
    backgroundColor: '#F4BF60',
    foregroundColor: '#FFFFFF',
    fontSize: 18
  }
]
export default {
  name: 'SchedulingEngineMeasure',
  components: {
    MyContainer,
    MyHeader,
    MyMain,
    TrendDialog
  },
  data() {
    return {
      loading: false,
      category: 'AI', // 应用类型
      scene: '', // 应用场景
      indicatorType: '', // 指标类型
      indicatorName: '', // 指标名称
      sceneLoading: false,
      indicatorNameLoading: false,
      categoryOptions: APP_CATEGORY, // 应用类型 选项
      sceneOptions: [], // 应用场景 选项
      indicatorTypeOptions: INDICATOR_TYPE, // 指标类型 选项
      indicatorNameOptions: [], // 指标名称 选项
      exportLoading: false,
      showMind: true,
      mindData: null,
      jmInstance: null,
      jmOptions: {
        container: 'jsmind_container',
        editable: true, // 设置为可编辑
        theme: 'primary', // 设置主题颜色（蓝色）
        mode: 'side',
        support_html: true,
        view: {
          engine: 'svg', // 思维导图各节点之间线条的绘制引擎
          hmargin: 20, // 思维导图距容器外框的最小水平距离
          vmargin: 20, // 思维导图距容器外框的最小垂直距离
          line_width: 12, // 思维导图线条的粗细
          line_color: '#2CCDE3', // 思维导图线条的颜色
          draggable: true,
          hide_scrollbars_when_draggable: false
        },
        default_event_handle: {
          enable_mousedown_handle: true,
          enable_click_handle: true,
          enable_dblclick_handle: false,
          enable_mousewheel_handle: true
        },
        layout: {
          hspace: 120, // 节点之间的水平间距
          vspace: 20, // 节点之间的垂直间距
          pspace: 20 // 节点与连接线之间的水平间距（用于容纳节点收缩/展开控制器）
        }
      },
      showTrendDialog: false,
      trendInfo: {}
    }
  },
  created() {},
  mounted() {
    this.initData()
  },
  methods: {
    /**
     * @description: 指标名称查询
     * @param {*} query
     * @return {*}
     */
    indicatorNameRemoteQuery(query) {
      this.indicatorNameLoading = true
      getIndicatorName({
        category: this.category,
        scene: this.scene,
        indicatorType: this.indicatorType,
        key: query
      })
        .then((res) => {
          if (Array.isArray(res.data)) {
            this.indicatorNameOptions = res.data.map((item) => {
              return {
                label: item,
                value: item
              }
            })
          }
        })
        .finally(() => {
          this.indicatorNameLoading = false
        })
    },
    /**
     * @description: 应用场景查询
     * @param {*} query
     * @return {*}
     */
    sceneRemoteQuery(query) {
      this.sceneLoading = true
      getIndicatorScene({
        category: this.category,
        scene: query
      })
        .then((res) => {
          if (Array.isArray(res.data)) {
            this.sceneOptions = res.data.map((item) => {
              return {
                label: item,
                value: item
              }
            })
          }
        })
        .finally(() => {
          this.sceneLoading = false
        })
    },
    /**
     * @description: 指标名称 变化
     * @param {*} val
     * @return {*}
     */
    indicatorNameChange(val) {},
    /**
     * @description: 指标类型 变化
     * @param {*} val
     * @return {*}
     */
    indicatorTypeChange(val) {
      this.indicatorName = ''
      this.indicatorNameOptions = []
      this.indicatorNameRemoteQuery('')
    },
    /**
     * @description: 应用场景 变化
     * @param {*} val
     * @return {*}
     */
    sceneChange(val) {
      this.indicatorType = ''
      this.indicatorTypeOptions = INDICATOR_TYPE
      this.indicatorName = ''
      this.indicatorNameOptions = []
      this.indicatorNameRemoteQuery('')
    },
    /**
     * @description: 应用类型 变化
     * @param {*} val
     * @return {*}
     */
    categoryChange(val) {
      this.scene = ''
      this.sceneOptions = []
      this.sceneRemoteQuery('')
      this.indicatorType = ''
      this.indicatorTypeOptions = INDICATOR_TYPE
      this.indicatorName = ''
      this.indicatorNameOptions = []
      this.indicatorNameRemoteQuery('')
    },
    /**
     * @description: 导出
     * @return {*}
     */
    exportClick() {
      this.exportLoading = true // 展示导出loading
      // 请求
      getMesaureExport()
        .then((response) => {
          const fileNames =
            response.headers['content-disposition'].split("filename*=utf-8''") // 读取文件名
          const fileName =
            fileNames.length > 1
              ? decodeURIComponent(fileNames[1])
              : '算网度量模型.xlsx' // 解析文件名
          const blob = new Blob([response.data], {
            type: 'application/vnd.ms-excel'
          }) // 新建blob
          const elementA = document.createElement('a') // 创建 element a
          elementA.style.display = 'none' // 设置不可见
          elementA.href = window.URL.createObjectURL(blob) // 设置href
          elementA.download = fileName // 设置名称
          document.body.appendChild(elementA) // 添加到body
          elementA.click() // 模拟点击
          window.URL.revokeObjectURL(elementA.href) // 释放内存
        })
        .catch((err) => {
          console.log(err)
          this.$message.error('导出失败，请稍候再试') // 导出失败
        })
        .finally(() => {
          this.exportLoading = false // 取消loading
        })
    },
    drawMind(measureData) {
      this.mindData = {
        /* 思维导图的数据格式 */
        meta: {
          name: '算网度量模型',
          author: 'xzhang@pmlabs.com',
          version: '0.1'
        },
        format: 'node_tree',
        data: {
          id: 'root', // 根节点
          isroot: true,
          topic: '应 用',
          'background-color': '#F440DB', // 节点颜色
          'foreground-color': '#FFFFFF', // 节点字体颜色
          'font-size': 20,
          'font-weight': 600,
          children: measureData
        }
      }
      if (this.jmInstance) {
        this.showMind = false
      }
      setTimeout(() => {
        this.showMind = true
        this.$nextTick(() => {
          // eslint-disable-next-line new-cap
          this.jmInstance = new jsMind(this.jmOptions)
          this.jmInstance.show(this.mindData)
        })
      }, 100)
    },
    /**
     * @description: 递归处理度量树状数据
     * @param {*} children
     * @param {*} level
     * @param {*} idPrefix
     * @return {*}
     */
    recurseHandleMeasureData(children, level, idPrefix) {
      children.forEach((child, index) => {
        const id = idPrefix + '-' + level + '-' + index
        child.oid = child.id
        child.id = id
        child['topic'] = child.msg
        if (
          level === 2 &&
          !isEmptyString(child.computeArch) &&
          child.computeArch.toUpperCase() === 'GPU'
        ) {
          // GPU类型微服务增加图标
          child[
            'topic'
          ] = `<div style="display: flex;align-items: center;"><span>${child.msg}</span><div style="margin: 2px 0 0 3px;display: inline-block;line-height: 20px;padding: 0 8px;border-radius: 12px;background: rgba(255,255,255,0.8);color: #21BFD4;font-size: 12px;">${child.computeArch}</div> </div>`
        }
        child['background-color'] = MIND_STYLES[level - 1].backgroundColor
        child['foreground-color'] = MIND_STYLES[level - 1].foregroundColor
        child['font-size'] = MIND_STYLES[level - 1].fontSize
        child['font-weight'] = 600
        if (Array.isArray(child.children)) {
          this.recurseHandleMeasureData(child.children, level + 1, id)
        } else {
          child['background-color'] = 'unset'
          child[
            'topic'
          ] = `<div ><span style="display: inline-block;height: 100%;padding: 0 10px;margin-right: 10px;background-color: ${
            MIND_STYLES[level - 1].backgroundColor
          }">${
            child.msg
          }</span><span style="font-size: 16px;cursor: pointer;box-sizing: border-box;display: inline-block;height: 36px;padding: 0 15px;background: #D9EDFF;color: #027DEC;border-radius: 5px;border: 1px solid #027DEC;">查看</span></div>`
        }
      })
    },
    /**
     * @description: jsmind点击
     * @return {*}
     */
    jsmindCtnClick() {
      const selectedNode = this.jmInstance.get_selected_node()
      if (selectedNode && selectedNode.id) {
        this.jmInstance.set_node_color(
          selectedNode.id,
          selectedNode.data['background-color'],
          selectedNode.data['foreground-color']
        )
        if (
          !(
            Array.isArray(selectedNode.children) &&
            selectedNode.children.length > 0
          )
        ) {
          this.showTrendDialog = true
          this.trendInfo = {
            id: selectedNode.parent.data['oid'] || ''
          }
        }
      }
    },
    /**
     * @description: 处理数据
     * @param {*} measureData
     * @return {*}
     */
    handleDataAndDraw(measureData) {
      this.recurseHandleMeasureData(measureData, 1, 'level')
      this.drawMind(measureData)
    },
    /**
     * @description: 获取度量模型数据
     * @return {*}
     */
    getMeasureData() {
      this.loading = true
      getIndicatorCase({
        category: this.category,
        scene: this.scene,
        indicatorType: this.indicatorType,
        indicatorName: this.indicatorName
      })
        .then((res) => {
          const measureData =
            res.data && Array.isArray(res.data.children)
              ? res.data.children
              : []
          this.handleDataAndDraw(measureData)
        })
        .finally(() => {
          this.loading = false
        })
    },
    /**
     * @description: 重置搜索框
     * @return {*}
     */
    resetClick() {
      this.scene = ''
      this.sceneOptions = []
      this.sceneRemoteQuery('')
      this.indicatorType = ''
      this.indicatorName = ''
      this.indicatorNameOptions = []
      this.indicatorNameRemoteQuery('')
      this.getMeasureData()
    },
    /**
     * @description: 搜索
     * @return {*}
     */
    queryClick() {
      this.getMeasureData()
    },
    /**
     * @description: 初始化数据
     * @return {*}
     */
    initData() {
      this.queryClick()
      this.sceneRemoteQuery('')
      this.indicatorNameRemoteQuery('')
    }
  }
}
</script>

<style lang="less" scoped>
@import "@/assets/css/common.less";

.container {
  overflow-y: auto;
  min-height: 600px;
  height: calc(100vh - 90px);

  .jsmind-wrapper {
    height: calc(100vh - 230px);
    background-image: radial-gradient(#e6e6e6 7%, transparent 0);
    background-size: 40px 40px;
  }

  .jsmind-ctn {
    height: 100%;

    /deep/ jmnode {
      box-shadow: unset;
      padding: 0 10px;
      height: 36px;
      line-height: 36px;
      &.selected {
        transition: 3s;
      }
    }
  }
}
</style>
